package it.antonio.ilpizze.db.index.hash.file;

import it.antonio.ilpizze.db.index.hash.Element;
import it.antonio.ilpizze.db.index.hash.ElementList;
import it.antonio.ilpizze.db.index.hash.HashTable;
import it.antonio.ilpizze.db.index.utils.FPerst;
import it.antonio.ilpizze.db.io.IOConstants;
import it.antonio.ilpizze.db.io.IOFile;

public abstract class FileHashTable<K,V> extends HashTable<K, V> implements IOConstants {
	
	/*
	 * degree/size/list/entries
	 */
	private IOFile file;
	private FPerst<K> keyPersister;
	private FPerst<V> valuePersister;
	
	private int degree;
	
	private FileHashTable(IOFile file, FPerst<K> keyPersister, FPerst<V> valuePersister) {
		this.file = file;
		this.keyPersister = keyPersister;
		this.valuePersister = valuePersister;
		
		file.position(0);
		degree = file.readInt();
		
	}

	@Override
	protected int degree() {
		return degree;
	}

	@Override
	protected ElementList<K,V> elementList() {
		long position = SIZE_INT +SIZE_LONG;
		
		return new FileElementList<K, V>(degree, file, position, keyPersister, valuePersister);
	}

	@Override
	protected Element<K,V> createElement(int hash, K key, V value) {
		file.position(SIZE_INT);
		long position = file.readLong();
		
		file.position(position);
		
		file.writeInt(hash);
		keyPersister.persist(file, key);
		valuePersister.persist(file, value);
		file.writeLong(-1);
		
		FileElement<K, V> entry = new FileElement<K, V>(file, position, keyPersister, valuePersister);
		
		file.position(SIZE_INT);
		file.writeLong(position + entry.space());
		
		return entry;
	}
	public static <K, V> FileHashTable<K,V> getOrCreate(IOFile file, int degree, FPerst<K> keyPersister, FPerst<V> valuePersister){
		if(file.size() == 0){
			file.writeInt(degree);
			file.writeLong(SIZE_INT + SIZE_LONG + (SIZE_LONG * degree));
			for(int i = 0; i < degree; i++){
				file.writeLong(-1);
			}
		}
		return new FileHashTable<K, V>(file, keyPersister, valuePersister){

			@Override
			protected int hashFunction(K key) {
				return key.hashCode();
			}
			
		};
		
	}
}
